
类模板通常对其实例化的模板参数使用多个操作(包括构造和析构)。这可能会使，这些模板参数必须为所有成员函数，提供所有必要的操作，而模板参数只需要提供所需的必要操作(而不是可能需要)即可。

例如，类Stack<>提供成员函数printOn()打印堆栈中的全部内容，并对每个元素使用操作符<{}<:

\begin{lstlisting}[style=styleCXX]
template<typename T>
class Stack {
	...
	void printOn(std::ostream& strm) const {
		for (T const& elem : elems) {
			strm << elem << ' '; // 对每个元素使用<<
		}
	}
};
\end{lstlisting}

对于没有定义操作符<{}<的类型，仍然可以使用这个类:

\begin{lstlisting}[style=styleCXX]
Stack<std::pair<int,int>> ps; // 注意: std::pair<>不支持<<
ps.push({4, 5}); // OK
ps.push({6, 7}); // OK
std::cout << ps.top().first << '\n'; // OK
std::cout << ps.top().second << '\n'; // OK
\end{lstlisting}

只在使用printOn()时代码才会出错，因为不能实例化特定元素类型的操作符<{}<:

\begin{lstlisting}[style=styleCXX]
ps.printOn(std::cout); // ERROR: 元素类型不支持操作符<<
\end{lstlisting}

\subsubsubsection{2.3.1\hspace{0.2cm}概念}

先来看一个问题:如何知道模板需要哪些操作才能实例化?“概念”通常用来表示模板库中需要的约束。例如，C++标准库依赖于随机访问迭代器和默认可构造函数等概念。

目前(如C++17)，概念只能通过文字进行表达(如代码注释)。这可能会成为一个严重的问题，因为不遵守约束可能会导致大量的错误消息(参见9.4)。

多年来，也有一些方法和试验支持将概念定义和验证为一种语言特性。然而，到C++17为止，还这样的方法还没标准化。

从C++11开始，可以通过使用static\_assert和预定义类型特征来检查约束。例如:

\begin{lstlisting}[style=styleCXX]
template<typename T>
class C
{
	static_assert(std::is_default_constructible<T>::value,
	"Class C requires default-constructible elements");
	...
};
\end{lstlisting}

使用默认构造函数，若没有这个断言，编译会失败。然而，错误消息描述的是整个模板实例化的过程，从最初的实例化原因到检测到错误的实际模板的定义(参见章节9.4)。

但需要更复杂的代码来检查，例如:T类型的对象是够提供了特定的成员函数，或者是否有可用的小于操作符。相关的示例，请参见第19.6.3节。

有关C++概念的详细讨论，请参阅附录E。















